using System.Drawing;
using System.IO;
using System.Net.Http.Headers;
using System.Reflection;
using System.Security.Policy;
using System.Text.RegularExpressions;

namespace Web_rongmeiti_sys.PublishToRongMeiTi
{
    /// <summary>
    /// 文章里面文件、图片过滤，提取（文件/图片）url上传到甲甲平台中，
    /// 成功的url再替换信息报送原本的url
    /// </summary>
    /// 创建时间：2023-6-16 11:29:40。作者：whl
    public class ArticleContentFileFilterHandler
    {

        /// <summary>
        ///文件上传到甲甲检查，是否存在url？ code=1存值，code=2不存在。
        ///message为存在的甲甲url
        /// </summary>
        /// <typeparam name="TEventArgs">传入参数类型</typeparam>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns> code=1存在，code=2不存在</returns>
        public delegate ResultNews MyEventHandler<TEventArgs>(object? sender, TEventArgs e);

        /// <summary>
        /// 上传文件到甲甲之前触发。返回值ResultNews：code=1存在，code=2不存在
        /// </summary>
        /// <remarks>
        /// 创建时间：2023-7-12 13:45:33，作者：whl
        /// </remarks>
        public static event MyEventHandler<RongmeitiFileInfo> FileUploadBefore;

        /// <summary>
        /// 事件触发通知,小图片数量有多少，TEventArgs 为文章原始id；
        /// </summary>
        /// 添加时间：2023-8-16 11:21:03，作者：whl
        public static event EventHandler<string> ImgCalcAmount;

        /// <summary>
        /// 文章里面文件、图片过滤，提取（文件/图片）url上传到甲甲平台中，
        /// 甲甲限制了单文件最大30MB,超过上传失败，文章累计附件大小不超过50MB
        /// </summary>
        /// <param name="html"></param>
        ///  <param name="articleId">文章id</param>
        /// <returns>返回文件列表，key为原url，value为甲甲平台的url</returns>
        /// 创建时间：2023-6-16 09:27:28，作者：whl
        //public static async Task<Result<Dictionary<string, string>?>> HtmlImgOrFileFilter(string html, string articleId, string account)
        public static async Task<Result<Dictionary<string, string>?>> HtmlImgOrFileFilter(string html, Web_rongmeiti_sys.Model.Article article)
        {
            string articleId = article.ArticleId;

            /*  附件url
             "attachments": [
			{
				"newsId": "5c9ca9ff-d77a-460e-b0b6-3e3b7e71c857",
				"newsNum": "whl_06ea2cba198f470ebeef05b651080b05",
				"attachmentType": "image",
				"attachmentUrl": "https://xx.xxx.com/NewsFiles/2023/7/31/01a76d94d7f64690a834c10a6b2f2b9b/6382477910158196179876959.jpg",
				"spAttachmentUrl": null,
				"fileName": "6382477910158196179876959.jpg",
				"id": "32a6026b-ebbb-4dfc-ab5c-08db91a851d9"
			},             
             */
            Dictionary<string, string>? dict = new Dictionary<string, string>();
            string errorMsg = string.Empty;


            //获取文章里面所有图片<img>标签  <img[\s\S]*?>
            var img_collom = Regex.Matches(html, "<img[\\s\\S]*?>", RegexOptions.IgnoreCase);

            var imgList = img_collom.Distinct(new EqualityComparer_URL());
            if (imgList.Count() == 0)
            {
                //没有图片，则查找有附件没得？
                goto SEARCH_FILE;
            }
            foreach (Match fileUrl_reg in imgList)
            {
                string imgTag = fileUrl_reg.Value;

                //解析图片src
                var collom_src = Regex.Matches(imgTag, "(?<=src\\s*=\\s*\")\\S+(?=\"{1})", RegexOptions.IgnoreCase);
                var findSrc = collom_src.FirstOrDefault();
                if (findSrc == null)
                {
                    continue;
                }

                string fileUrl = findSrc.Value;
                if (dict.ContainsKey(fileUrl) || string.IsNullOrWhiteSpace(fileUrl))
                {
                    continue;
                }

                //添加时间：2023-8-1 11:35:01，作者：whl
                if (GetHaveDomain(fileUrl))
                {
                    continue;
                }

                //将fileUrl_reg.Value地址生成MD5与数据库存值比对，有记录则不上传，
                //直接使用数据库存的甲甲url，没得记录则新增
                var fileInfo = new RongmeitiFileInfo()
                {
                    Original_URL = fileUrl
                };

                ResultNews? findResult = FileUploadBefore?.Invoke(new Result() { Code = 1 }, fileInfo);

                //传入参数Code=1、13表示（查询历史记录），为3则新增记录
                if (findResult != null && (findResult.Value.code == 1 || findResult.Value.code == 13))
                {
                    // findResult 如果是小图片，添加时间：2023-8-16 16:07:33，作者：whl
                    if (findResult.Value.code == 13)
                    {
                        //检查图片url是否重复了？找到图片数量
                        int realImgCount = img_collom.Where(g =>
                        {
                            //提取img标签的src
                            var mathImgSrc = Regex.Match(g.Value, "(?<=src\\s*=\\s*\")\\S+(?=\"{1})", RegexOptions.IgnoreCase);
                            if (mathImgSrc.Value == fileUrl)
                            {
                                return true;
                            }
                            return false;
                        }).Count();
                        for (int i = 0; i < realImgCount; i++)
                        {
                            //通知一次，数量- 1
                            LogHelpter.AddLog($"宽度小于20的图片,even22，通知，articleId={articleId}", null, "small_image_ImgCalcAmount");
                            ImgCalcAmount?.Invoke(1, articleId);
                        }
                    }

                    //表示已经上传过
                    dict.Add(fileUrl, findResult.Value.message);
                    continue;
                }

                //获取图片文件名
                string fileName = MyResourceRequestHandler.GetUrlFileName(fileUrl);

                //检查后缀名，没有后缀名将导致文件上传失败
                string extendName = Path.GetExtension(fileName);
                string imgExtend = ".jpg|.jpeg|.png|.webp|.jfif|.bmp|.gif";
                if (string.IsNullOrWhiteSpace(extendName) || !imgExtend.Contains(extendName, StringComparison.OrdinalIgnoreCase))
                {
                    fileName += ".jpg";
                }

                byte[] fileByter = null;
                try
                {
                    //下载信息报送中的图片
                    fileByter = await DownImgAsync(fileUrl);
                    if (fileByter.Length == 0)
                    {
                        continue;
                    }

                    //读取图片大小，添加时间：2023-8-16 11:01:42，作者：whl
                    Stream imgStream = new MemoryStream(fileByter);
                    System.Drawing.Image img = Bitmap.FromStream(imgStream);

                    //文件信息，2023-8-16 16:29:06
                    fileInfo.Img_width = img.Width;
                    fileInfo.Img_height = img.Height;
                    fileInfo.File_size_kb = Convert.ToDecimal(fileByter.Length / (decimal)1024); /* KB */

                    if (img.Width < 20 && img.Height < 20)  //宽度小于20，为图标/很小的图片，不计入图片数量
                    {
                        LogHelpter.AddLog($"宽度小于20的图片，通知，articleId={articleId}", null, "small_image_ImgCalcAmount");
                        ImgCalcAmount?.Invoke(1, articleId);
                    }
                    imgStream?.DisposeAsync();
                }
                catch (Exception ex)
                {
                    var ex1 = ex.InnerException ?? ex;
                    string msg = $"下载第三方系统文件异常,url={fileUrl},{ex1.Message}，文章html={html}";
                    LogHelpter.AddLog(msg, null, "HtmlImgOrFileFilter_error");

                    //跳过下载失败的文件，修改时间：2023-8-3 18:02:10，whl
                    //return new Result<Dictionary<string, string>?>(msg);
                    continue;
                }
                //处理图片，压缩图片，修改时间2023-11-7 18:22:00 whl
                int maxWidth = 0;
                if (!int.TryParse(MyConfigReader.GetConfigValue("allow_img_max_width"), out maxWidth))
                {
                    maxWidth = 1300;
                }
                System.IO.Stream inStream = new System.IO.MemoryStream();
                inStream.Write(fileByter, 0, fileByter.Length);
                System.IO.Stream outStream = new System.IO.MemoryStream();
                try
                {
                    //执行压缩图片
                    Web_rongmeiti_sys.Model.ImageHandle.CompressImgByte(maxWidth, maxWidth, inStream, outStream);
                    outStream.Position = 0;
                }
                catch (Exception ex)
                {
                    LogHelpter.AddLog($"图片压缩失败url={fileUrl},{ex.ToString()}", "CompressImg");
                    continue;
                }
                //压缩后的图片
                byte[] fileYaSuoByte = new byte[outStream.Length];
                outStream.Read(fileYaSuoByte, 0, (int)outStream.Length);
                
                inStream.Dispose();
                outStream.Dispose();

                var uploadImgResult = await UploadFileAsync(fileYaSuoByte, articleId, fileName, fileUrl, article.Cnpc_account, article.Cnpc_password);
                if (uploadImgResult.code != 200)
                {
                    return new Result<Dictionary<string, string>?>()
                    {
                        Code = 500,
                        Msg = uploadImgResult.message
                    };
                }
                string rongmeitiImgUrl = uploadImgResult.result?.ToString();

                if (!string.IsNullOrWhiteSpace(rongmeitiImgUrl))
                {
                    //Code = 3表示新增文件上传记录，2023-7-12 15:05:42
                    FileUploadBefore?.Invoke(new Result() { Code = 3, Msg = rongmeitiImgUrl }, fileInfo);

                    dict.Add(fileUrl, rongmeitiImgUrl);
                }
            }

        SEARCH_FILE:
            //提取<a>标签，<a[\s\S]*?>
            var a_List = Regex.Matches(html, "<a[\\s\\S]*?>", RegexOptions.IgnoreCase);
            if (a_List.Count == 0)
            {
                goto File_done;
            }
            var a_List3 = a_List.Distinct(new EqualityComparer_URL());
            foreach (Match item in a_List3)
            {
                //a标签html
                string a_html = item.Value;

                //提取附件a标签的href。(?<=href\s*=\s*")\S+(?="{1})
                var fileList = Regex.Match(a_html, "(?<=href\\s*=\\s*\\\")\\S+(?=\\\"{1})", RegexOptions.IgnoreCase);
                if (fileList == null)
                {
                    continue;
                }
                string fileUrl = fileList.Value;
                var fileInfo = new RongmeitiFileInfo()
                {
                    Original_URL = fileUrl
                };
                //添加时间：2023-7-12 10:40:27，作者：whl
                if (dict.ContainsKey(fileUrl) || string.IsNullOrWhiteSpace(fileUrl))
                {
                    continue;
                }

                //判断是否已经在中石油域名下了，添加时间：2023-8-1 11:35:01，作者：whl                   
                if (GetHaveDomain(fileUrl))
                {
                    continue;
                }
                string fileName = MyResourceRequestHandler.GetUrlFileName(fileUrl);

                //检查后缀名
                string extendName = Path.GetExtension(fileName);
                string fileExtendName_check = ".jpg|.jpeg|.jfif|.png|.gif|.bmp|.webp|.zip|.rar|.xls|.xlsx|.doc|.docx|.rtf|.pdf|.ppt|.pptx|.mp4|.avi|.mov";
                if (string.IsNullOrWhiteSpace(extendName) || !fileExtendName_check.Contains(extendName.ToLower()))
                {
                    continue;
                }

                //将fileUrl_reg.Value地址生成MD5与数据库存值比对，有记录则不上传，
                //直接使用数据库存的甲甲url，没得记录则新增
                ResultNews? findResult = FileUploadBefore?.Invoke(new Result() { Code = 1 }, fileInfo);
                if (findResult != null && findResult.Value.code == 1)
                {
                    //表示已经上传过
                    dict.Add(fileUrl, findResult.Value.message);
                    continue;
                }

                //下载文章内容中的文件
                byte[] fileByter = null;
                try
                {
                    fileByter = await DownImgAsync(fileUrl);
                    if (fileByter.Length == 0)
                    {
                        continue;
                    }
                }
                catch (Exception ex)
                {
                    var ex1 = ex.InnerException ?? ex;
                    string msg = $"下载第三方系统文件异常,url={fileUrl},{ex1.Message}，文章html={html}";
                    LogHelpter.AddLog(msg, null, "HtmlImgOrFileFilter_error");

                    //修改时间：2023-8-3 18:00:55，跳过下载不了的文件
                    //return new Result<Dictionary<string, string>?>(msg);
                    continue;
                }

                //检查后缀名
                if (!string.IsNullOrWhiteSpace(extendName))
                {
                    goto UPLOAD_FILE;    /* 有后缀名的文件直接走上传 */
                }
                if (!fileExtendName_check.Contains(extendName, StringComparison.OrdinalIgnoreCase))
                {
                    //查找文件真实格式
                    byte[] checkRealFileType = new byte[50];
                    //Array.Copy(fileByter, 0, checkRealFileType, 0, 50);
                    Array.Copy(fileByter, checkRealFileType, 50);

                    var fileType = FileTypeCheck.fileSignature.Where(g =>
                    {
                        foreach (byte[] bytes in g.Value)
                        {
                            byte[] curFileSig = new byte[bytes.Length];
                            Array.Copy(checkRealFileType, curFileSig, bytes.Length);
                            if (curFileSig.SequenceEqual(bytes))
                            {
                                //验证格式通过
                                return true;
                            }
                        }
                        return false;
                    }).FirstOrDefault();
                    if (string.IsNullOrWhiteSpace(fileType.Key))
                    {
                        fileName = fileName + ".zip";
                    }
                    else
                    {
                        fileName = fileName + fileType.Key.ToLower();
                    }
                }

            //上传文件到甲甲平台
            UPLOAD_FILE:
                var uploadFileResult = await UploadFileAsync(fileByter, articleId, fileName, fileUrl, article.Cnpc_account, article.Cnpc_password);
                if (uploadFileResult.code != 200)
                {
                    return new Result<Dictionary<string, string>?>()
                    {
                        Code = 500,
                        Msg = uploadFileResult.message
                    };
                }
                string rongmeiti_FileUrl = uploadFileResult.result?.ToString();

                //上传文件记录
                if (!string.IsNullOrWhiteSpace(rongmeiti_FileUrl))
                {
                    fileInfo.File_size_kb = Convert.ToDecimal(fileByter.Length / (decimal)1024); /* KB */

                    //Code = 3表示新增文件上传记录，2023-7-12 15:05:42
                    FileUploadBefore?.Invoke(new Result() { Code = 3, Msg = rongmeiti_FileUrl }, fileInfo);

                    dict.Add(fileUrl, rongmeiti_FileUrl);
                }
            }
        File_done:
            return new Result<Dictionary<string, string>?>(dict);
        }

        /// <summary>
        /// 判断是否包含域名，包含返回true
        /// </summary>
        /// <param name="fileUrl"></param>
        /// <returns></returns>
        /// 创建时间：2023-8-3 14:02:21，作者：whl
        private static bool GetHaveDomain(string fileUrl)
        {
            if (fileUrl.Contains("xx.xxx.com")
                 || fileUrl.Contains("xx.xxx1.com")
                 || fileUrl.Contains("xx.xxx2.com")
                 || fileUrl.Contains("xx.xxx3.com")
             )
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="fileUrl">文件url</param>
        /// <returns></returns>
        /// 创建时间：2023-5-29 16:50:55。作者：whl
        public static async Task<byte[]> DownImgAsync(string fileUrl)
        {
            HttpClient httpClient = new HttpClient();
            return await httpClient.GetByteArrayAsync(fileUrl);
        }

        /// <summary>
        /// 上传（图片/文件）到甲甲
        /// </summary>
        /// <param name="fileBuffer">文件字节</param>
        /// <param name="articleId">文章id，数字类型</param>
        ///  <param name="fileName">文件原名</param>
        ///  <param name="orignUrl">文件原url</param>
        /// <returns></returns>
        /// 创建时间：2023-5-29 17:01:34。作者：whl
        public static async Task<ResultNews> UploadFileAsync(byte[] fileBuffer, string articleId, string fileName, string orignUrl, string account, string cnpcPassword)
        {
            if (fileBuffer == null || fileBuffer.Length == 0)
            {
                return new ResultNews() { message = $"错误，参数fileBuffer为0字节，参数orignUrl={orignUrl}", code = 500 };
            }
            //string uploadUrl = "https://xx.xxx.com/api/Common/UploadFiles?NewsNum=" + articleId;
            string uploadUrl = MyConfigReader.GetConfigValue("pf_eip_upload_url") + articleId;

            //登录身份信息
            string? identityCookie = AuthCookieHelpter.GetIdentityCookie(account);
        Send_two:
            int errorCount = 0;
            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.Add("mimeType", "multipart/form-data");
            //httpClient.DefaultRequestHeaders.Add("userSelectOrgCode", ArticlePublishHandler.publishUser.result.orgCode);
            httpClient.DefaultRequestHeaders.Add("Cookie", identityCookie);/* 身份验证 */

            MultipartFormDataContent multipartFormData = new MultipartFormDataContent();
            //multipartFormData.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
            multipartFormData.Add(new ByteArrayContent(fileBuffer), "files", fileName);

            var responseMessage = await httpClient.PostAsync(uploadUrl, multipartFormData);

            //加入时间：2023-9-4 17:34:05，whl
            string back_content = await responseMessage.Content.ReadAsStringAsync();
            if (responseMessage.StatusCode == System.Net.HttpStatusCode.Unauthorized)
            {
                LogHelpter.AddLog("上传文件" + articleId + "，甲甲报401,甲甲：" + back_content, null, "UploadFileAsync_error");

                //错误次数累计
                errorCount++;
                if (errorCount > 2)
                {
                    string msg = "发布失败，甲甲报401，没有获取到身份信息，请联系管理员";
                    return new ResultNews() { message = msg, code = 500 };
                }

                //重新登录，获取身份信息，获取cookie的值
                var loginResult = LoginHandler.LoginCall(account, cnpcPassword);

                httpClient.Dispose();
                responseMessage.Dispose();

                //获取身份 cookie
                identityCookie = AuthCookieHelpter.GetIdentityCookie(account);

                goto Send_two;
            }

            string resultJson = await responseMessage.Content.ReadAsStringAsync();
            /*
{"code":422,"message":"参数不合法","result":[{"field":null,"message":"Failed to read the request form. Missing content-type boundary."}]}
{"code":422,"message":"参数不合法","result":[{"field":null,"message":"Failed to read the request form. Multipart body length limit 16384 exceeded."}]}
{"code":400,"message":"不支持此文件()格式！","result":"Common.Model.FriendlyException: 不支持此文件()格式！ 
             */
            /**
响应成功：
{ "code":200,"message":"","result":"https://xx.xxx.com/NewsFiles/2023/5/29/202305291550153554/httpkp2.cri.jpg"}
             */
            LogHelpter.AddLog($"上传图片到甲甲平台，文章id={articleId},原url={orignUrl}，结果：{resultJson}", null, "Upload");

            //            if (responseMessage.IsSuccessStatusCode)
            //            {
            //                ResultNews fileResult = Newtonsoft.Json.JsonConvert.DeserializeObject<ResultNews>(resultJson);
            //                if (fileResult.code == 200)
            //                {
            //                    return fileResult.result?.ToString();
            //                }
            //            }

            ResultNews fileResult = Newtonsoft.Json.JsonConvert.DeserializeObject<ResultNews>(resultJson);
            return fileResult;
        }

    }
}
